import os;
import sys;

sys.path.append(os.environ['SOURCE_HOME'] + '/webapp');
sys.path.append(os.environ['SOURCE_HOME'] + '/library/python');

import imp;
import dbx;
import stdx;
import webx;
import time;
import logging;
import datetime;
from ctypes import *;

cgimap = None;
httpid = None;
httpsvr = None;
httpath = None;
httport = None;
httphost = None;
dbpoolmap = None;
cgimapfile = None;
cgimaptime = None;

def pystr(str):
	if str: return str.decode();
	return None;

def cppstr(str):
	if str: return str.encode();
	return None;

def initsvr(path):
	global httpsvr;
	httpsvr = cdll.LoadLibrary(path + 'etc/plugin/bin/InitSystem.so');
	httpsvr.SetLogFlag.argtypes = [c_int];
	httpsvr.WriteLog.argtypes = [c_char_p, c_char_p];
	httpsvr.GetId.restype = c_int;
	httpsvr.GetPort.restype = c_int;
	httpsvr.GetHost.restype = c_char_p;
	httpsvr.GetSequence.restype = c_char_p;
	httpsvr.GetConfig.restype = c_char_p;
	httpsvr.GetConfig.argtypes = [c_char_p];
	httpsvr.GetMimeType.restype = c_char_p;
	httpsvr.GetMimeType.argtypes = [c_char_p];
	httpsvr.GetParameter.restype = c_char_p;
	httpsvr.GetParameter.argtypes = [c_char_p];
	httpsvr.GetRouteHost.restype = c_char_p;
	httpsvr.GetRouteHost.argtypes = [c_char_p];
	httpsvr.SetCgiAccess.argtypes = [c_char_p, c_char_p];
	httpsvr.DisableSession.restype = c_int;
	httpsvr.DisableSession.argtypes = [c_char_p];
	httpsvr.CreateSession.restype = c_int;
	httpsvr.CreateSession.argtypes = [c_char_p, c_int];
	httpsvr.GetSession.restype = c_char_p;
	httpsvr.GetSession.argtypes = [c_char_p, c_char_p];
	httpsvr.SetSession.restype = c_int;
	httpsvr.SetSession.argtypes = [c_char_p, c_char_p, c_char_p];
	httpsvr.GetLastRemoteStatus.restype = c_int;
	httpsvr.GetRemoteResult.restype = c_char_p;
	httpsvr.GetRemoteResult.argtypes = [c_char_p, c_char_p, c_char_p, c_char_p];

def writelog(tag, msg, err = None):
	if err: logging.exception(err);
	if httpsvr: httpsvr.WriteLog(tag.encode(), msg.encode());
	else: stdx.puts(msg);

def setup(path):
	global httpid;
	global httpsvr;
	global httpath;
	global httport;
	global httphost;
	global dbpoolmap;
	global cgimapfile;
	global cgimaptime;
	if path:
		httpath = path;
		try:
			initsvr(path);
			if httpid == None: httpid = httpsvr.GetId();
			if httport == None: httport = httpsvr.GetPort();
			if httphost == None: httphost = pystr(httpsvr.GetHost());
			if cgimapfile == None: cgimapfile = os.path.dirname(os.path.realpath(__file__)) + '/' + '__init__.py';
			cgimaptime = os.path.getmtime(cgimapfile);
		except BaseException as e:
			writelog('ERR', 'system error[%s]' % str(e), e);
			return False;
	if httpsvr: cfg = stdx.LoadConfig(pystr(httpsvr.GetConfig(cppstr('DATABASE_CONFIGFILE_PATH'))));
	else: cfg = stdx.LoadConfig(os.environ['SOURCE_HOME'] + '/webapp/etc/dbconfig.lua');
	name = cfg['NAME'];
	pool = None;
	if name.find('$') >= 0 or name.find('%') >= 0 or name.find('`') >= 0:
		with os.popen('echo %s' % name) as fd: name = fd.read().strip();
	if name.find('/') >= 0 or name.find('\\') >= 0:
		import pysqlite3;
		pool = dbx.DBConnectPool(pysqlite3, name);
	else:
		import pymysql;
		pool = dbx.DBConnectPool(pymysql, name, cfg['HOST'], cfg['PORT'], cfg['USER'], cfg['PASSWORD']);
	dbx.SetConnectPool(pool);
	with dbx.GetConnect() as db:
		dbpoolmap = {};
		for item in db.queryArray('SELECT ID,TYPE,NAME,HOST,PORT,USER,PASSWD,CHARSET FROM T_XG_DBETC WHERE ENABLED>0'):
			type = item['type'].lower();
			dbid = item['id'];
			pool = None;
			try:
				name = item['name'];
				charset = item['charset'].lower().replace('-', '');
				if name.find('$') >= 0 or name.find('%') >= 0 or name.find('`') >= 0:
					with os.popen('echo %s' % name) as fd: name = fd.read().strip();
				if type.find('mysql') >= 0:
					import pymysql;
					pool = dbx.DBConnectPool(pymysql, name, item['host'], int(item['port']), item['user'], item['passwd'], charset);
				elif type.find('sqlite') >= 0:
					import pysqlite3;
					pool = dbx.DBConnectPool(pysqlite3, name);
				else:
					writelog('ERR', 'unsupported database[%s]' % dbid);
			except BaseException as e:
				writelog('ERR', 'connect database[%s] failed[%s]' % (dbid, str(e)), e);
			if pool:
				writelog('IMP', 'connect database[%s] success' % dbid);
				dbpoolmap[dbid] = pool;
	reloadpython();
	return True;

def getcgimap():
	global cgimap;
	reloadpython();
	return cgimap;

def reloadpython():
	global cgimap;
	try:
		import pyc.__init__;
		cgimap = imp.reload(pyc.__init__).getcgimap();
		return True;
	except BaseException as e:
		writelog('ERR', 'reload python cgimap failed', e);
		return False;

def process(url, head, data):
	try:
		if cgimapfile:
			global cgimaptime;
			tm = os.path.getmtime(cgimapfile);
			if tm > cgimaptime and reloadpython(): cgimaptime = tm + 0.001;
		key = url.lower();
		if key not in cgimap:
			if key == 'reloadpython':
				if reloadpython(): return stdx.json({'code': stdx.XG_OK});
				else: return stdx.json({'code': stdx.XG_SYSERR});
			return stdx.XG_NOTFOUND;
		app = HttpProcesser(url, head, data);
		res = cgimap[key](app);
		return (res, app.getHeader());
	except BaseException as e:
		writelog('ERR', '[' + url + '] ' + str(e), e);
		return stdx.json({'code': stdx.XG_SYSERR});

class HttpProcesser(webx.HttpRequest):
	def __init__(self, url, head, data):
		webx.HttpRequest.__init__(self, head, data);
		self._rsphead = {};
	def __len__(self):
		return len(self._data);
	def __getattr__(self, attr):
		return self.getParameter(attr);
	def getPort(self):
		return httport;
	def getHost(self):
		return httphost;
	def getPath(self):
		return httpath;
	def getSequence(self):
		return pystr(httpsvr.GetSequence());
	def getConfig(self, key):
		return pystr(httpsvr.GetConfig(cppstr(key)));
	def getVariable(self, key):
		return pystr(httpsvr.GetParameter(cppstr(key)));
	def getLastRemoteStatus(self):
		return httpsvr.GetLastRemoteStatus();
	def getRemoteResult(self, path, param = None, contype = None, cookie = None):
		return pystr(httpsvr.GetRemoteResult(cppstr(path), cppstr(param), cppstr(contype), cppstr(cookie)));
	def simpleResponse(self, code):
		return "{\"code\":" + str(code) + "}";
	def setHeader(self, key, val):
		self._rsphead[key] = val;
		return self;
	def getMimeType(self, key):
		return pystr(httpsvr.GetMimeType(cppstr(key)));
	def setContentType(self, mime):
		return self.setHeader('Content-Type', mime);
	def getHeader(self, key = None):
		if key: return self._rsphead[key];
		else: return self._rsphead;
	def dbconnect(self, dbid = None):
		conn = None;
		global dbpoolmap;
		if dbid == None or len(dbid) <= 0: conn = dbx.GetConnect();
		if dbid in dbpoolmap: conn = dbpoolmap[dbid].get();
		if conn: conn._log = writelog;
		return conn;
	def trace(self, tag, msg, err = None):
		writelog(tag, msg, err);
		return self;
	def getSessionId(self):
		sid = self.getHeadParameter('Cookie');
		if len(sid) <= 0:
			sid = self.getHeadParameter('cookie');
			if len(sid) <= 0: return self.getParameter('sid');
		pos = sid.find('sid=');
		if pos < 0: return self.getParameter('sid');
		pos = pos + 4;
		end = sid.find(';', pos);
		if end < pos: return sid[pos:].lstrip(' \r\n\t').rstrip(' \r\n\t');
		else: return sid[pos:end].lstrip(' \r\n\t').rstrip(' \r\n\t');
	def setSessionId(self, sid):
		self.setHeader('Set-Cookie', 'sid=' + sid + ';max-age=' + str(90 * 24 * 3600));
	def createSession(self, sid, sec):
		return httpsvr.CheckSession(cppstr(sid), cppstr(sec));
	def disableSession(self, sid = None):
		if sid == None: sid = self.getSessionId();
		if sid: httpsvr.DisableSession(cppstr(sid));
	def setSession(self, key, val, sid = None):
		if sid == None: sid = self.getSessionId();
		if sid: return httpsvr.SetSession(cppstr(sid), cppstr(key), cppstr(val));
		else: return stdx.XG_PARAMERR;
	def getSession(self, key = None, sid = None):
		if sid == None: sid = self.getSessionId();
		if sid: return pystr(httpsvr.GetSession(cppstr(sid), cppstr(key)));
		return None;
	def checkSession(self, keylist = None, sid = None):
		res = [];
		if isinstance(keylist, list) or isinstance(keylist, tuple):
			for key in keylist:
				val = self.getSession(key, sid);
				if val == None: return XG_TIMEOUT;
				res.append(val);
		else:
			val = self.getSession(str(keylist), sid);
			if val == None: return XG_TIMEOUT;
			res.append(val);
		return res;
